"""
-------------------------------
- File_Name: login.py
- Date: 2025/2/15
- Author: yangzhide
- Email: xxzjyzd@126.com
- Description: 系统核心接口
-------------------------------
"""

from fastapi import APIRouter, Depends, Body, HTTPException, Path
from fastapi.security import OAuth2PasswordRequestForm
from tortoise.queryset import Q
from app.core.ctx import CTX_USER, CtxUser
from app.core.security import verify_password, user_to_create_token
from app.models import RoleButton
from app.models.system.admin import User, Button, Menu, RoleMenu, Role, UserRole
from config import get_api_environment_var
from app.schemas.system.system import Token, UserInfo, ConstantMenu, RefreshTokenIn, RoleMenuIdsOut
from app.schemas import BaseResponse
from app.utils.responseUtil import ResponseUtil
from app.core.security import get_current_user
from app.utils.system import get_user_button, build_route_tree
from typing import Union

api_environment = get_api_environment_var()

router = APIRouter()
tags = ["认证"]
description = "用户jwt认证、登录相关"


async def get_user(username: str, password: str):
    """获取用户信息"""
    user_obj: User = await User.get_or_none(user_code=username)  # 使用用户编号
    if not user_obj:
        return False
    if not verify_password(password, user_obj.password):
        return False
    return user_obj


async def authenticate_user(username: str, password: str):
    """验证用户名及密码"""
    user = await get_user(username, password)
    return user


@router.post("/auth/login", summary="用户登录", response_model=Union[Token, BaseResponse])
async def login(from_data: OAuth2PasswordRequestForm = Depends()):
    user = await authenticate_user(from_data.username, from_data.password)
    if not user:
        raise HTTPException(status_code=401, detail="无效的用户名或密码")
    if user.status == "2":
        raise HTTPException(status_code=401, detail="当前用户状态不可用")

    # 存储到请求上下文,用户名称及角色编号
    user_role_id = await UserRole.filter(user_id=user.id).values_list("role_id", flat=True)
    user_role_code = await Role.filter(id__in=user_role_id).values_list("role_code", flat=True)
    user_ctx = CtxUser(
        user_name=user.user_name,
        user_code=user.user_code,
        user_role_id=user_role_id,
        user_role_code=user_role_code,
    )
    CTX_USER.set(user_ctx)
    access_token, refresh_token = await user_to_create_token(user)
    # 保证fastapi文档正确提取到token及前端格式,手动处理兼容格式
    return {
        "code": "200",
        "msg": "生成token",
        "access_token": access_token,
        "refresh_token": refresh_token,
        "token_type": "bearer",
        "data": {
            "token": access_token,
            "refreshToken": refresh_token,
            "token_type": "bearer"
        }
    }


@router.get("/auth/getUserInfo", summary="获取用户信息", response_model=BaseResponse[UserInfo])
async def get_userinfo(user_obj: User = Depends(get_current_user)):
    # 角色code
    ctx_user = CTX_USER.get()
    user_obj.roles = ctx_user.user_role_code

    # 角色按钮
    if "R_Super" in ctx_user.user_role_code:
        # 所有按钮权限
        user_obj.buttons = [button.button_code for button in await Button.all()]
    else:
        # 其他用户权限按钮
        user_obj.buttons = await get_user_button(user_obj)


    return ResponseUtil.success_response(data=user_obj, msg="请求用户信息成功")


@router.post("/auth/refreshToken", summary="刷新token", response_model=Union[Token, BaseResponse])
async def _(refresh_token: RefreshTokenIn = Body()):
    # 获取当前用户信息
    user = await get_current_user(token=refresh_token.refresh_Token)
    access_token, refresh_token = await user_to_create_token(user)
    # 保证fastapi文档正确提取到token及前端格式,手动处理兼容格式
    return {
        "code": "200",
        "msg": "刷新生成token",
        "access_token": access_token,
        "refresh_token": refresh_token,
        "token_type": "bearer",
        "data": {
            "token": access_token,
            "refreshToken": refresh_token,
            "token_type": "bearer"
        }
    }


@router.get("/route/getUserRoutes", dependencies=[Depends(get_current_user)], summary="用户前端路由树")
async def _():
    """
    返回当前用户路由菜单树\n
    超级管理员返回所有菜单
    :return:
    """
    # 异步上下文
    ctx_user = CTX_USER.get()
    if "R_Super" in ctx_user.user_role_code:
        # 返回所有路由菜单
        role_routes: list[Menu] = await Menu.filter(constant=False,status="1").order_by("id")  # 非常量路由
    else:
        # 根据role_menu 关系表遍历添加相应路由菜单
        # 所有的路由菜单id
        role_menu_ids = await RoleMenu.filter(role_id__in=ctx_user.user_role_id).values_list("menu_id", flat=True)
        # 查询非隐藏菜单中对应菜单id
        role_routes = await Menu.filter(Q(id__in=role_menu_ids) & Q(hide_in_menu=False))
    # 去重
    role_routes = list(set(role_routes))
    # 递归生成菜单
    menu_tree = await build_route_tree(role_routes, simple=True)

    data = {"code": 200, "data": {"routes": menu_tree,"home":"home" }, "msg": "用户路由菜单查询成功"}
    return data


@router.get("/auth/getRoleMenuIds/{id}", dependencies=[Depends(get_current_user)],
            summary="角色菜单id/按钮code列表及首页",
            response_model=BaseResponse[RoleMenuIdsOut])
async def _(_ids: int | str = Path(alias="id", description="角色id")):
    """
    返回角色菜单id列表\n
    返回角色按钮code列表\n
    超级管理员返回所有菜单id
    :return:
    """
    role_obj = await Role.get_or_none(id=_ids)
    if not role_obj:
        raise HTTPException(status_code=404, detail=f"角色信息不存在【id={_ids}】")
    # 超级管理员返回所有
    if role_obj.role_code == "R_Super":
        role_menu_ids = await Menu.filter(constant=False).values_list("id", flat=True)
        role_menu_buttons = await Button.all().values_list("button_code", flat=True)
    else:
        # 菜单
        role_menu_ids = await RoleMenu.filter(role_id=_ids).values_list("menu_id", flat=True)
        # 按钮
        role_menu_button_ids = await RoleButton.filter(role_id=_ids).values_list("button_id", flat=True)
        role_menu_buttons = await Button.filter(id__in=role_menu_button_ids).values_list("button_code", flat=True)
    data = RoleMenuIdsOut(role_home=role_obj.role_home, menu_ids=role_menu_ids, menu_buttons=role_menu_buttons)
    return {"code": 200, "data": data.model_dump(), "msg": "角色菜单id列表"}


@router.get("/route/getConstantRoutes", summary="常量路由菜单", response_model=BaseResponse[ConstantMenu])
async def _():
    # 所有常量路由菜单
    menu_objs = await Menu.filter(constant=True, hide_in_menu=True).order_by("id")
    # 给每个对象添加属性meta
    for menu_obj in menu_objs:
        menu_obj.meta = menu_obj
    return ResponseUtil.success_response(data=menu_objs, msg="查询常量路由成功")
